package com.dingreading.cloud.mall.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.DateUtil;
import com.dingreading.cloud.common.util.EnumType;
import com.dingreading.cloud.common.util.ExceptionLogs;
import com.dingreading.cloud.common.util.IpUtil;
import com.dingreading.cloud.common.util.alipay.AliPayApi;
import com.dingreading.cloud.common.util.alipay.AlipayConfig;
import com.dingreading.cloud.common.util.wechat.*;
import com.dingreading.cloud.mall.entity.CooperPayOrder;
import com.dingreading.cloud.mall.entity.OrderForm;
import com.dingreading.cloud.mall.service.CooperPayOrderService;
import com.dingreading.cloud.mall.service.OrderFormServiceV5;
import com.dingreading.cloud.mall.util.PayDealV3Util;
import io.seata.spring.annotation.GlobalTransactional;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;

@RefreshScope
@RestController
@RequestMapping(value = "/payCallback")
@Api(tags = "支付-回调结果管理")
public class PayCallBackController {

    // 叮叮文化
    @Value("${wx.mchId}")
    private String mchId;
    @Value("${wx.mchKey}")
    private String mchKey;

    // 叮叮书房文化
    @Value("${wx.sf.mchId}")
    private String shMchId;
    @Value("${wx.sf.mchKey}")
    private String shMchKey;

    // ACEC
    @Value("${wx.nj.mchId}")
    private String njMchId;
    @Value("${wx.nj.mchKey}")
    private String njMchKey;

    @Value("${payNotifyUrl}")
    private String notifyUrl;

    //    @Resource
//    protected OrderFormService orderFormService;
    @Resource
    protected OrderFormServiceV5 orderFormService;
    @Resource
    protected CooperPayOrderService cooperPayOrderService;


    @GlobalTransactional
    @ApiOperation(value = "微信-扫码支付回调接口")
    @PostMapping(value = "/wxpay/scanNotify", produces = "application/json; charset=UTF-8")
    public void scanNotify(HttpServletRequest request, HttpServletResponse response) {
        try {
//            System.out.println("微信-扫码支付通知回调接口");
            String result = PaymentKit.readData(request);
//            获取返回的信息内容中各个参数的值
            Map<String, String> map = PaymentKit.xmlToMap(result);
//            System.out.println("微信-扫码支付通知回调接口 = " + map.toString());
            String appid = map.get("appid");
            String openid = map.get("openid");
            String mchid = map.get("mch_id");
            String isSubscribe = map.get("is_subscribe");
            String nonceStr = map.get("nonce_str");
            String productId = map.get("product_id");
            String sign = map.get("sign");
            String attach = map.get("attach");
            PayExtraDto payExtra = PayExtraUtil.getPayExtra(attach);

            Map<String, String> packageParams = new HashMap<>();
            packageParams.put("appid", appid);
            packageParams.put("openid", openid);
            packageParams.put("mch_id", mchid);
            packageParams.put("is_subscribe", isSubscribe);
            packageParams.put("nonce_str", nonceStr);
            packageParams.put("product_id", productId);
            String mchKey = "";
            if (mchid.equals(this.mchId))
                mchKey = this.mchKey;
            else if (mchid.equals(this.shMchId))
                mchKey = this.shMchKey;
            String packageSign = PaymentKit.createSign(packageParams, mchKey);
            Map<String, String> params = new HashMap<>();
            if (productId.startsWith(EnumType.CodeCategory.TOB.getType())) {
                if (payExtra.getOrderType().equals(EnumType.CodeType.CGSP.getType())) {
                    //根据product_id查询商品订单详情
                    OrderForm orderForm = orderFormService.getByCode(null, productId);
                    params.put("total_fee", WxDataUtils.formatDoubleTOInt(Double.parseDouble(String.valueOf(orderForm.getPayPrice())), 100.0) + "");
                    params.put("body", orderForm.getName());
                } else if (payExtra.getOrderType().equals(EnumType.CodeType.HZDD.getType())) {
                    // 叮叮收银台
                    CooperPayOrder orderForm = cooperPayOrderService.getByCode(productId);
                    params.put("total_fee", WxDataUtils.formatDoubleTOInt(Double.parseDouble(String.valueOf(orderForm.getPayPrice())), 100.0) + "");
                    params.put("body", orderForm.getProjectName());
                }
            } else if (productId.startsWith(EnumType.CodeCategory.TOC.getType())) {
                if (payExtra.getOrderType().equals(EnumType.CodeType.HYDD.getType())) {
//                    MemberOrders memberOrders = memberOrdersService.getByCode(null, productId);
//                    params.put("total_fee", WxDataUtils.formatDoubleTOInt(Double.parseDouble(String.valueOf(memberOrders.getPayAmount())), 100.0) + "");
//                    params.put("body", memberOrders.getItemName());
                }
            }

            params.put("appid", appid);
            params.put("mch_id", mchid);
            params.put("openid", openid);
            params.put("out_trade_no", productId);
            params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
            params.put("notify_url", notifyUrl);

            params.put("trade_type", EnumType.TradeType.WECHAT_NATIVE.getType());
            params.put("spbill_create_ip", IpUtil.getIpAddr(request));
            params.put("sign", PaymentKit.createSign(params, mchKey));

            Map<String, String> payResult = WxPayBusiness.scanCode(PaymentKit.toXml(params));
            if (payResult != null) {
                String returnCode = payResult.get("return_code");
                String resultCode = payResult.get("result_code");

                if (StringUtils.isNotBlank(returnCode) && StringUtils.isNotBlank(resultCode) && "SUCCESS".equalsIgnoreCase(returnCode) && "SUCCESS".equalsIgnoreCase(resultCode)) {
                    // 以下字段在return_code 和result_code都为SUCCESS的时候有返回
                    String prepayId = payResult.get("prepay_id");

                    Map<String, String> prepayParams = new HashMap<>();
                    prepayParams.put("return_code", "SUCCESS");
                    prepayParams.put("return_msg", "OK");
                    prepayParams.put("appId", appid);
                    prepayParams.put("mch_id", mchid);
                    prepayParams.put("nonce_str", System.currentTimeMillis() + "");
                    prepayParams.put("prepay_id", prepayId);
                    String prepaySign = null;
                    if (sign.equals(packageSign)) {
                        prepayParams.put("result_code", "SUCCESS");
                    } else {
                        //result_code为FAIL时，添加该键值对，value值是微信告诉客户的信息
                        prepayParams.put("result_code", "FAIL");
                        prepayParams.put("err_code_des", "订单失效");
                    }
                    prepaySign = PaymentKit.createSign(prepayParams, mchKey);
                    prepayParams.put("sign", prepaySign);
                    String xml = PaymentKit.toXml(prepayParams);
                    //处理业务完毕
                    BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
                    out.write(xml.getBytes());
                    out.flush();
                    out.close();
                }
            }
        } catch (Exception e) {
            System.out.println(ExceptionLogs.getErrorInfoFromException(e));
        }
    }

    @GlobalTransactional
    @ApiOperation(value = "微信支付通知回调接口")
    @RequestMapping(value = "/wxpay/notifyUrl")
    public void notifyUrl(HttpServletRequest request, HttpServletResponse response) {
        System.out.println("微信支付通知回调接口");
        try {
            String xmlResult = WxDataUtils.getXmlRequest(request);
            SortedMap<String, String> resultMap = WxDataUtils.xml2Map(xmlResult);

            // 根据商户号id，取商户号秘钥
            String mchid = resultMap.get("mch_id");
            String mchKey = this.mchKey;
            if (StringUtils.isNotBlank(mchid)) {
                if (mchid.equals(this.mchId))
                    mchKey = this.mchKey;
                else if (mchid.equals(this.shMchId))
                    mchKey = this.shMchKey;
                else if (mchid.equals(this.njMchId))
                    mchKey = this.njMchKey;
            }

            SortedMap<String, String> map = WxPayBusiness.Init().paySuccess(response, resultMap, mchKey);
//            System.out.println("微信支付通知回调结果\n" + map.toString());
            if (map.get("result_code").equalsIgnoreCase("success")) {
                if (StringUtils.isNotBlank(map.get("out_trade_no"))) {
                    Date callBackTime = DateUtil.getNowDatetime();
                    String code = map.get("out_trade_no");
                    String tradeType = map.get("trade_type");
                    String buyerId = map.get("openid");
                    String tradeNo = map.get("transaction_id");
                    Date date = DateUtil.formatDateTime(map.get("time_end"), "yyyyMMddHHmmss");
                    String payTime = DateUtil.getDefaultTimeStr(date);
                    String attach = map.get("attach");
                    PayExtraDto payExtra = PayExtraUtil.getPayExtra(attach);

                    R<Object> result = new R<>();
                    if (code.startsWith(EnumType.CodeCategory.TOB.getType())) {
                        String tradeTypeName = "";
                        if (tradeType.equals(EnumType.TradeType.WECHAT_NATIVE.getType())) {
                            tradeTypeName = EnumType.TradeType.WECHAT_NATIVE.getName();
                        }
                        if (payExtra.getOrderType().equals(EnumType.CodeType.CGSP.getType())) {
                            // 采购商品
                            result = PayDealV3Util.payOkGoodsOrder(code, EnumType.PayType.WECHAT.getType(), tradeType,
                                    tradeTypeName, buyerId, tradeNo, payTime, null, null,
                                    null, 1);
                        } else if (payExtra.getOrderType().equals(EnumType.CodeType.HZDD.getType())) {
                            // 收银台
                            result = PayDealV3Util.payOkCooperOrderPayOrder(code, EnumType.PayType.WECHAT.getType(), tradeType,
                                    tradeTypeName, buyerId, tradeNo, payTime);
                        } else if (payExtra.getOrderType().equals(EnumType.CodeType.SQZC.getType())) {
                            // 暑期专场
//                            result = PayDealV3Util.payOkSummerStudentOrder(result, code, EnumType.PayType.WECHAT.getType(), tradeType,
//                                    tradeTypeName, buyerId, tradeNo, payTime);
                        }
                    } else if (code.startsWith(EnumType.CodeCategory.TOC.getType())) {
                        if (payExtra.getOrderType().equals(EnumType.CodeType.HYDD.getType())) {
                            // 推广活动
//                            result = PayDealV3Util.payOkMemberOrder(result, code, EnumType.PayType.WECHAT.getDesc(),
//                                    tradeType, buyerId, tradeNo, payTime, callBackTime);
                        }
                    } else if (code.startsWith(EnumType.CodeCategory.NJ.getType())) {
                        if (payExtra.getOrderType().equals(EnumType.CodeCategory.NJ.getType())) {
                            // 南京参会票
                            result = PayDealV3Util.payOkNjTicketOrder(code, tradeType, buyerId, tradeNo, payTime, callBackTime);
                        }
                    } else if (code.startsWith(EnumType.CodeCategory.RD.getType())) {
                        if (payExtra.getOrderType().equals(EnumType.CodeType.RD.getType())) {
                            // 名师堂体验
                            result = PayDealV3Util.payOkReadstarPayOrder(code, tradeType, buyerId, tradeNo, payTime, callBackTime);
                        }
                    }
                    if (result.getSt() == 0) {
//                        System.out.println(result.getData());
                    } else {
                        System.out.println(result.getMsg());
                    }
                }
            } else {
                System.out.println("微信支付通知回调失败");
            }
        } catch (Exception e) {
            System.out.println(ExceptionLogs.getErrorInfoFromException(e));
        }

    }

    @GlobalTransactional
    @ApiOperation(value = "支付宝-扫码支付通知回调接口")
    @PostMapping(value = "/alipay/scanNotify", produces = "application/json; charset=UTF-8")
    public void scanNotify(
            HttpServletRequest request
    ) {
        try {
//            System.out.println("支付宝-扫码支付通知回调接口");
            Map<String, String> map = AliPayApi.toMap(request);
//            System.out.println("支付宝-扫码支付通知回调结果\n" + map.toString());
            String appId = map.get("app_id");
            boolean flag = false;
            if (appId.equals(AlipayConfig.APPID)) {
                flag = AlipaySignature.rsaCheckV1(map, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
            } else if (appId.equals(AlipayConfig.SF_APPID)) {
                flag = AlipaySignature.rsaCheckV1(map, AlipayConfig.SF_ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
            }
            if (flag) {
                if ("TRADE_SUCCESS".equalsIgnoreCase(map.get("trade_status"))) {
                    if (StringUtils.isNotBlank(map.get("out_trade_no"))) {
                        Date callBackTime = DateUtil.getNowDatetime();
                        String code = map.get("out_trade_no");
                        String tradeType = EnumType.TradeType.ALIPAY_NATIVE.getType();
                        String buyerId = map.get("buyer_id");
                        String tradeNo = map.get("trade_no");
                        String payTime = map.get("gmt_payment");
                        String body = map.get("body");
                        PayExtraDto payExtra = PayExtraUtil.getPayExtra(body);

                        R<Object> result = new R<>();
                        if (code.startsWith(EnumType.CodeCategory.TOB.getType())) {
                            if (payExtra.getOrderType().equals(EnumType.CodeType.CGSP.getType())) {
                                // 采购商品
                                result = PayDealV3Util.payOkGoodsOrder(code, EnumType.PayType.ALIPAY.getType(),
                                        tradeType, EnumType.TradeType.ALIPAY_NATIVE.getName(), buyerId, tradeNo, payTime,
                                        null, null, null, 1);
                            } else if (payExtra.getOrderType().equals(EnumType.CodeType.HZDD.getType())) {
                                // 收银台
                                result = PayDealV3Util.payOkCooperOrderPayOrder(code, EnumType.PayType.ALIPAY.getType(), tradeType,
                                        EnumType.TradeType.ALIPAY_NATIVE.getName(), buyerId, tradeNo, payTime);
                            }
                        } else if (code.startsWith(EnumType.CodeCategory.TOC.getType())) {
                            if (payExtra.getOrderType().equals(EnumType.CodeType.HYDD.getType())) {
                                // 推广活动
//                                result = PayDealV3Util.payOkMemberOrder(result, code, EnumType.PayType.ALIPAY.getDesc(),
//                                        tradeType, buyerId, tradeNo, payTime, callBackTime);
                            }
                        }
                        if (result.getSt() == 0) {
//                            System.out.println(result.getData());
                        } else {
                            System.out.println(result.getMsg());
                        }
                    }
                }
            } else {
                System.out.println("支付宝扫码支付通知回调失败");
            }
        } catch (Exception e) {
            System.out.println(ExceptionLogs.getErrorInfoFromException(e));
        }
    }

    @GlobalTransactional
    @ApiOperation(value = "支付宝-异步通知")
    @RequestMapping(value = "/alipay/notifyUrl")
    public void notifyUrl(HttpServletRequest request) throws Exception {
        try {
//            下单成功后，支付宝服务器通知商户服务，并把这笔订单的状态通知给商户，商户根据返回的这笔订单的状态，修改网站订单的状态，比如等待买家付款状态，买家已经付款等待卖家发货
//            System.out.println("支付宝支付后异步回调 begin...");
            // 获取支付宝POST过来反馈信息
            Map<String, String> map = AliPayApi.toMap(request);
//            System.out.println("支付宝支付回调结果\n" + map.toString());
            String appId = map.get("app_id");
            boolean verifyResult = false;
            if (appId.equals(AlipayConfig.APPID)) {
                verifyResult = AlipaySignature.rsaCheckV1(map, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
            } else if (appId.equals(AlipayConfig.SF_APPID)) {
                verifyResult = AlipaySignature.rsaCheckV1(map, AlipayConfig.SF_ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
            }
            if (verifyResult) {
                // 验证成功
                // TODO 请在这里加上商户的业务逻辑程序代码 异步通知可能出现订单重复通知 需要做去重处理
                if ("TRADE_SUCCESS".equalsIgnoreCase(map.get("trade_status"))) {
                    if (StringUtils.isNotBlank(map.get("out_trade_no"))) {
                        Date callBackTime = DateUtil.getNowDatetime();
                        String code = map.get("out_trade_no");
                        String buyerId = map.get("buyer_id");
                        String tradeNo = map.get("trade_no");
                        String payTime = map.get("gmt_payment");
                        String body = map.get("body");
                        PayExtraDto payExtra = PayExtraUtil.getPayExtra(body);

                        R<Object> result = new R<>();
                        if (code.startsWith(EnumType.CodeCategory.TOB.getType())) {
                            if (payExtra.getOrderType().equals(EnumType.CodeType.CGSP.getType())) {
                                // 采购商品
                                result = PayDealV3Util.payOkGoodsOrder(code, EnumType.PayType.ALIPAY.getType(),
                                        EnumType.TradeType.ALIPAY_WAP.getType(), EnumType.TradeType.ALIPAY_WAP.getName(),
                                        buyerId, tradeNo, payTime, null, null, null, 1);
                            } else if (payExtra.getOrderType().equals(EnumType.CodeType.HZDD.getType())) {
                                // 收银台
                                result = PayDealV3Util.payOkCooperOrderPayOrder(code, EnumType.PayType.ALIPAY.getType(),
                                        EnumType.TradeType.ALIPAY_WAP.getType(), EnumType.TradeType.ALIPAY_WAP.getName(),
                                        buyerId, tradeNo, payTime);
                            } else if (payExtra.getOrderType().equals(EnumType.CodeType.SQZC.getType())) {
                                // 暑期专场
//                                result = PayDealV3Util.payOkSummerStudentOrder(result, code, EnumType.PayType.ALIPAY.getType(),
//                                        EnumType.TradeType.ALIPAY_WAP.getType(), EnumType.TradeType.ALIPAY_WAP.getName(),
//                                        buyerId, tradeNo, payTime);
                            }
                        } else if (code.startsWith(EnumType.CodeCategory.TOC.getType())) {
                            if (payExtra.getOrderType().equals(EnumType.CodeType.HYDD.getType())) {
                                // 推广活动
//                                result = PayDealV3Util.payOkMemberOrder(result, code, EnumType.PayType.ALIPAY.getDesc(),
//                                        EnumType.TradeType.ALIPAY_WAP.getType(), buyerId, tradeNo, payTime, callBackTime);
                            }
                        }

                        if (result.getSt() == 0) {
//                            System.out.println(result.getData());
                        } else {
                            System.out.println(result.getMsg());
                        }
                    }
                }
            } else {
                System.out.println("支付宝支付后异步回调 验证失败");
            }
        } catch (AlipayApiException e) {
            System.out.println(ExceptionLogs.getErrorInfoFromException(e));
        }
    }

}